/*
 * Eugen Stoian <stoian.e@gmail.com> 2010
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "Expression3D.h"
#include <MathParser.h>
Expression3D::Expression3D(const QStringList& varList,
                           const QString& xExpression,
                           const QString& yExpression,
                           const QString& zExpression,
                           QObject *parent)
        :Object(parent),_varList(varList),_xExpression(xExpression),_yExpression(yExpression),_zExpression(zExpression) {
}

Expression3D::Expression3D(QObject *parent)
        :Object(parent){
}

Object* Expression3D::clone() const{
    return new Expression3D(_varList,_xExpression,_yExpression,_zExpression);
}


const QStringList& Expression3D::variablesList() const {
    return _varList;
}

const QString& Expression3D::x() const {
    return _xExpression;
}

const QString& Expression3D::y() const {
    return _yExpression;
}

const QString& Expression3D::z() const {
    return _zExpression;
}

QString Expression3D::xSignature() const {
    QString sig = objectName()+"X[";
    int count = _varList.count();
    for(int i = 0; i < count; ++i){
        if(i < count-1){
            sig+=",";
        }
    }
    sig+="]";
    return sig;
}

QString Expression3D::ySignature() const {
    QString sig = objectName()+"Y[";
    int count = _varList.count();
    for(int i = 0; i < count; ++i){
        if(i < count-1){
            sig+=",";
        }
    }
    sig+="]";
    return sig;
}

QString Expression3D::zSignature() const {
    QString sig = objectName()+"Z[";
    int count = _varList.count();
    for(int i = 0; i < count; ++i){
        if(i < count-1){
            sig+=",";
        }
    }
    sig+="]";
    return sig;
}

QString Expression3D::xCode() const {
    QString code = objectName()+"X[";
    int count = _varList.count();
    for(int i = 0; i < count; ++i){
        code+=_varList[i];
        if(i < count-1){
            code+=",";
        }
    }
    code+="]=";
    code+=_xExpression;
    code+=".";
    return code;
}

QString Expression3D::yCode() const {
    QString code = objectName()+"Y[";
    int count = _varList.count();
    for(int i = 0; i < count; ++i){
        code+=_varList[i];
        if(i < count-1){
            code+=",";
        }
    }
    code+="]=";
    code+=_yExpression;
    code+=".";
    return code;
}

QString Expression3D::zCode() const {
    QString code = objectName()+"Z[";
    int count = _varList.count();
    for(int i = 0; i < count; ++i){
        code+=_varList[i];
        if(i < count-1){
            code+=",";
        }
    }
    code+="]=";
    code+=_zExpression;
    code+=".";
    return code;
}

SmartPtr<ExpressionTreeNode> Expression3D::xTree() const {
    MathParser::parse(xCode());
    SmartPtr<ExpressionTreeNode> node = MathParser::getTree(xSignature())->copy();
    if(node)
        MathParser::removeFun(xSignature());
    return node;
}

SmartPtr<ExpressionTreeNode> Expression3D::yTree() const{
    MathParser::parse(yCode());
    SmartPtr<ExpressionTreeNode> node = MathParser::getTree(ySignature())->copy();
    if(node)
        MathParser::removeFun(ySignature());
    return node;
}

SmartPtr<ExpressionTreeNode> Expression3D::zTree() const{
    MathParser::parse(zCode());
    SmartPtr<ExpressionTreeNode> node = MathParser::getTree(zSignature())->copy();
    if(node)
        MathParser::removeFun(zSignature());
    return node;
}

bool Expression3D::isValid() const{
    if(_varList.isEmpty()||_xExpression.isEmpty()||_yExpression.isEmpty()||_zExpression.isEmpty())
        return false;
    SmartPtr<ExpressionTreeNode> node = xTree();
    if(!node)
        return false;
    node = yTree();
    if(!node)
        return false;
    node = zTree();
    if(!node)
        return false;
    return true;
}

void Expression3D::setVariablesList(const QStringList& varList){
    _varList = varList;
    emit changed();
}

void Expression3D::setX(const QString& expr){
    _xExpression = expr;
    emit changed();
}

void Expression3D::setY(const QString& expr){
    _yExpression = expr;
    emit changed();
}

void Expression3D::setZ(const QString& expr){
    _zExpression = expr;
    emit changed();
}

QDataStream& operator<<(QDataStream& stream, const Expression3D& expr){
    stream << expr.objectName();
    int count = expr._varList.count();
    stream << count;
    for(int i = 0; i < count;++i)
        stream << expr._varList[i];
    stream << expr._xExpression;
    stream << expr._yExpression;
    stream << expr._zExpression;
    return stream;
}
QDataStream& operator>>(QDataStream& stream, Expression3D& expr){
    QString name;
    stream >> name;
    expr.setObjectName(name);
    int count;
    stream >> count;
    for(int i = 0; i < count; ++i){
        QString var;
        stream >> var;
        expr._varList.append(var);
    }

    stream >> expr._xExpression;
    stream >> expr._yExpression;
    stream >> expr._zExpression;

    return stream;
}
